package com.ljh.myrpc.server.tcp;

import cn.hutool.core.util.IdUtil;
import com.ljh.myrpc.RpcApplication;
import com.ljh.myrpc.model.RpcRequest;
import com.ljh.myrpc.model.RpcResponse;
import com.ljh.myrpc.model.ServiceMetaInfo;
import com.ljh.myrpc.protocol.*;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;
import io.vertx.core.net.NetSocket;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Slf4j
public class VertxTcpClient {
    public static RpcResponse doRequest(RpcRequest rpcRequest, ServiceMetaInfo serviceMetaInfo) throws Exception {
        // 发送TCP请求
        Vertx vertx = Vertx.vertx();
        NetClient netClient = vertx.createNetClient();
        CompletableFuture<Object> responseFuture = new CompletableFuture<>();
        netClient.connect(serviceMetaInfo.getServicePort(), serviceMetaInfo.getServiceHost(), result ->{
            if(result.succeeded()){
                log.info("Connect to TCP service");
                NetSocket socket = result.result();
                // 发送数据
                // 构造信息
                ProtocolMessage<RpcRequest> protocolMessage = new ProtocolMessage<>();
                ProtocolMessage.Header header = new ProtocolMessage.Header();
                header.setMagic(ProtocolConstant.PROTOCOL_MAGIC);
                header.setVersion(ProtocolConstant.PROTOCOL_VERSION);
                header.setSerializer((byte) ProtocolMessageSerializerEnum.
                        getEnumByValue(RpcApplication.getRpcConfig().getSerializer())
                        .getKey());
                header.setType((byte) ProtocolMessageTypeEnum.REQUEST.getKey());
                header.setRequestId(IdUtil.getSnowflakeNextId());
                protocolMessage.setHeader(header);
                protocolMessage.setBody(rpcRequest);
                // 编码请求
                try {
                    Buffer encodeBuffer = ProtocolMessageEncoder.encode(protocolMessage);
                    socket.write(encodeBuffer);
                } catch (Exception e) {
                    throw new RuntimeException("协议消息编码错误");
                }

                // 接受响应
                socket.handler(buffer -> {
                    try {
                        ProtocolMessage<RpcResponse> responseProtocolMessage = (ProtocolMessage<RpcResponse>) ProtocolMessageDecoder.decode(buffer);
                        responseFuture.complete(responseProtocolMessage.getBody());
                    } catch (Exception e) {
                        throw new RuntimeException("协议消息解码错误" + e);
                    }
                });
            }else{
                log.error("Failed to connect to TCP server");
                responseFuture.completeExceptionally(new RuntimeException("Failed to connect to TCP server"));
            }
        });
        // 阻塞，知道响应完成，才会继续向下执行
        RpcResponse rpcResponse = (RpcResponse) responseFuture.get();
        // 关闭连接
        netClient.close();
        return rpcResponse;
    }
}
